#include <iostream>
#include <cmath>
#include <chrono>
#include <thread>
#include <vector>
#include <mutex>
#include <sstream>
#include <iomanip>

using namespace std;

static const int MAX = 10e8;
static double sum = 0;

static mutex exclusive;

std::string nowTime()
{
    auto now = std::chrono::system_clock::now();
    auto inTime = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(localtime(&inTime), "%Y-%m-%d %X");
    return ss.str();
}

void worker(int min, int max)
{
    for (int i = min; i <= max; i++)
    {
        sum += sqrt(i);
    }
}

void concurrent_worker(int min, int max)
{
    double tmp_sum = 0;
    for (int i = min; i <= max; i++)
    {
        tmp_sum += sqrt(i);
    }
    exclusive.lock();
    sum += tmp_sum;
    exclusive.unlock();
}


void serial_task()
{
    cout << nowTime() << endl;
    auto start_time = chrono::steady_clock::now();
    sum = 0;
    worker(0, MAX);
    auto end_time = chrono::steady_clock::now();
    auto ms = chrono::duration_cast<chrono::milliseconds>(end_time - start_time).count();
    cout << nowTime() << " Serail task finish, " << ms << "ms consumed, Result: " << sum << endl;
}

void concurrent_task(int min, int max)
{
    auto start_time = chrono::steady_clock::now();

    unsigned concurrent_count = thread::hardware_concurrency();
    cout << nowTime() << " hardware_concurrency: " << concurrent_count << endl;
    vector<thread> threads;

    min = 0;
    sum = 0;

    for (unsigned int t = 0; t < concurrent_count; t++)
    {
        int range = max / concurrent_count * (t + 1);
        threads.push_back(thread(concurrent_worker, min, range));
        min = range + 1;
    }
    for (auto& t : threads)
    {
        t.join();
    }

    auto end_time = chrono::steady_clock::now();
    auto ms = chrono::duration_cast<chrono::milliseconds>(end_time - start_time).count();
    cout << nowTime() << " Concurrent task finish, " << ms << " ms consumed, Result: " << sum << endl;
}

int main()
{
    serial_task();
    concurrent_task(0, MAX);
    cout << "Hello World!" << endl;
    return 0;
}
